home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Tool Chest / Testing & Debugging / General tools / Audit app & dcmd / About Audit - text next >
Encoding:
Text File  |  1993-09-17  |  27.8 KB  |  374 lines  |  [TEXT/MSWD]

  1. Copyright © 1992-1992 Apple Computer Inc. All Rights Reserved    1.
  2.  
  3. The Audit Library        September 16, 1993
  4.  
  5.  
  6.  
  7.  
  8.  Copyright © 1992, Apple Computer Inc. All Rights Reserved — Preliminary Draft    1
  9.  
  10.  
  11. The Audit Library
  12. Martin Minow
  13. Developer Technical Support
  14.  
  15. Introduction
  16. The Audit Library allows you to add event tracing to all types of Macintosh code segments, including device drivers, callback routines, dynamically-loaded code segments, and applications. Except for the initialization routine, all functions may be called at any time, even within interrupt or I/O completion routines. The library is designed to be “fail-safe:” it has no error conditions and, barring a malicious attack, will either do what is requested or do nothing, but it should never crash or stall your program. In particular, if your application tries to log data when no audit record has been established, or there is no room in the audit record, your program will not stall, crash or damage the system.
  17. USAGE
  18. To use the Audit library, you must include its definition file, create an Audit record, store data, and read data. The following examples show this in the context of a single application; however real-world users would probably split the functions among separate applications; perhaps by creating the Audit record in an init or driver open routine, storing data in a driver or callback code-segment, and displaying data in a stand-alone application or MacsBug dcmd.
  19. Global Variable Definitions
  20. A very simple Audit display application might define the parameters it needs as global values:
  21.  
  22. #include "Audit.h"
  23. AuditPtr                gAuditPtr;        /* Returned by InitAudit and ReadAudit        */
  24. AuditEntry            gCurrentEntry;    /* Returned by ReadAudit                        */
  25. ProcessSerialNumber    gProcessSerialNumber;    /* Used by WakeUpAudit                */
  26. Boolean                gHasPSN;                    /* See WakeUpAudit example            */
  27.  
  28. Creating the Audit Record
  29. Using the above definitions, the following statements create and initialize an audit record:
  30.  
  31.         Boolean initiallyEnabled = TRUE;
  32.         Boolean preserveFirstEntries = FALSE;
  33.         gAuditPtr = InitAudit('Moof', 64, initiallyEnabled , preserveFirstEntries);
  34. The above call creates an audit record “named” Moof that can store 64 audit record entries. Auditing is initially enabled. If there is no room in the audit record, the first entry waiting for the display routine will be used for this entry (i.e., the last 64 entries will be retained). Note that InitAudit may only be called from applications or code-segments that can allocate memory. In the following example, it is called from a display application that also initializes the time format parameter handle and records the start times.
  35.  
  36. void
  37. InitializeAudit(
  38.         OSType            auditSelector
  39.     )
  40. {
  41.         /*
  42.          * Create an audit record that can hold 64 entries. Logging is
  43.          * enabled at start.
  44.          */
  45.         gAuditPtr = InitAudit(auditSelector, 64, TRUE, FALSE);
  46.         StartAuditing();        /* Wake me up when there is data. See below        */
  47.         AuditString(gAuditPtr, "\pHello world!");    /* Initial entry                */
  48. }
  49. Specifying the display application
  50. Under System 7, the display application should inform the Audit library that it is to be awakened from its event loop whenever data is stored in the audit record. This allows the display application to set a long sleep time when it calls WaitNextEvent. In the following example, StartAuditing should be called immediately after your display application creates an audit record (or calls GetAuditPtr to determine that an audit record already exists). StopAuditing should be called before your application exits.
  51.  
  52. void
  53. StartAuditing(void)
  54. {
  55.         OSErr                    status;
  56.         long                    gestaltResult;
  57.  
  58.         status = Gestalt(gestaltOSAttr, &gestaltResult);
  59.         if (status == noErr
  60.          && (gestaltResult & (1 << gestaltLaunchControl)) != 0) {
  61.             GetCurrentProcess(&oldPSN);
  62.             WakeUpAudit(gAuditPtr, &oldPSN);
  63.             gHasPSN = TRUE;
  64.         }
  65.         else {
  66.             gHasPSN = FALSE;
  67.         }
  68. }
  69.  
  70. void
  71. StopAuditing(void)
  72. {
  73.         if (gHasPSN)
  74.             WakeUpProcess(gAuditPtr, &oldPSN);
  75. }
  76. Once your application calls StartAuditing, it will receive an event whenever anything calls Audit for this audit record.
  77. Writing an Audit  Record Entry
  78. The following code sequence shows how the library might be used to log status errors. It would be called immediately after calling a library function. In the example, the application tries to read data from a file and logs any errors that are returned:
  79.  
  80.         status = FSRead(refNum, &bytesToRead, buffer);
  81.         if (status != noErr) {
  82.             if (status != eofErr) {
  83.                 /*
  84.                  * Unexpected error
  85.                  */
  86.                 AuditStatusLocation(gAuditPtr, 'Read', status);
  87.                 Audit(
  88.                     gAuditPtr,
  89.                     'Read',
  90.                     AuditFormat5(
  91.                         kAuditFormatSigned,
  92.                         kAuditFormatSigned,
  93.                         kAuditFormatUnsigned,
  94.                         kAuditFormatAddress
  95.                         kAuditFormatString
  96.                     ),
  97.                     (signed long) status,
  98.                     (signed long) refNum,
  99.                     bytesToRead,
  100.                     buffer,
  101.                     "\pFSRead"
  102.                 );
  103.             }
  104.         }
  105. This example shows two Audit calls: the AuditStatus macro stores the status code and a string that identifies the function that called it, while the general Audit call stores five values: the status code, device reference number, number of bytes, buffer address, and a labelling string.
  106. Reading an Audit  Record Entry
  107. A typical display application calls ReadAudit each time within its event loop, even if no event was returned:
  108.  
  109.         for (i = 0; i < 10; i++) {
  110.             if (ReadAudit(gAuditPtr, &gMissedDataCount, &gCurrentEntry) == FALSE)
  111.                 break;                    /* Nothing more to display    */
  112.             ProcessAuditEntry();
  113.         }
  114. Here, note that each pass through the event loop tries to process several audit records, exiting when the “to be done” queue is empty, or a reasonable number have been processed. Processing entries in a loop such as the one shown above may prevent a run-away asychronous process from absorbing the entire machine by saturating the audit record.
  115. Your display application would process an audit entry by formatting the entry record, including the timestamp, id code, and data. 
  116. Displaying the Audit Entry Data
  117. Two functions are provided (in file AuditEntryFormat.c) that convert the audit entry record into readable Pascal strings.
  118. •    The FormatAuditEntryTimestamp function determines the time that an audit entry was created, storing it in a Pascal string buffer. The  time is given in ISO-standard date format as  “yyyy.mm.dd hh.mm.ss.msec.” This is a fixed-length string whose format is independent of the user’s time and date formatting choice.
  119. •    The FormatAuditData function converts the data portion of the audit entry record, storing it as a Pascal string.
  120. For example, the following C sequence may be used to print an audit entry record:
  121. void
  122. FormatEntryData(void)
  123. {
  124.         Str255                    timestamp;
  125.         Str255                    content;
  126. #define ENTRY    (gCurrentEntry)
  127.  
  128.         /*
  129.          * gLogIndex is the sequence number of this entry. Note that it tracks
  130.          * missing entries: i.e. it records the sequence of Audit calls.
  131.          */
  132.         gLogIndex = gLogIndex + ENTRY.lostData + 1;
  133.         FormatAuditEntryTimestamp(gAuditPtr, &ENTRY, timestamp);
  134.         FormatAuditEntryData(&ENTRY, content);
  135.         printf("%6lu", gLogIndex);
  136.         printf(" %.*s:", timestamp[0], ×tamp[1]);
  137.         printf(" %.*s\n", content[0], &content[1]);
  138. }
  139. The source of FormatAuditEntryTimestamp and FormatAuditEntryData should be consulted to see how to process the entry data, including converting the timestamp and “decompiling” the formatted data. The printf format writes the pascal string in a format compatible with the ANSI standard. Think C users can also use an implementation-specific format designator for Pascal strings: "%#s".
  140. AUDIT RECORD DATA
  141. The audit library uses a private data area in the System Heap to store its information. InitAudit and GetAuditPtr return a pointer to that area, and all other functions use that pointer as a parameter. The contents of the area are private: your application does not access this record directly, but calls library routines. This is important to prevent asychronous calls (from interrupt routines, for example) from accessing the data simultaneously.
  142. Your display application does need to understand the format of the audit entry record that is returned by ReadAudit. This contains the information that was stored as a result of an Audit call.
  143. Audit Entry Contents
  144. ReadAudit. if successful, returns an audit record entry. This is a C structure with the following format:
  145. typedef struct AuditEntry {
  146.     unsigned long    tickCount;    /* TickCount() at call    */
  147.     unsigned long    lostData;    /* Lost record count    */
  148.     OSType    idCode;    /* Why are we logging    */
  149.     unsigned long    format;    /* Format of the data    */
  150.     unsigned long    data[8];    /* 32-bytes of data    */
  151. } AuditEntry, *AuditEntryPtr;
  152. The structure elements are used as follows:
  153. tickCount    This value timestamps each entry: it is the value of Ticks when the element was written into the log.
  154. lostData    This is set to the number of entries that were not logged because the log area was full. Each time Audit stores a log entry, it copies its internal lostData counter to the new audit entry, then sets its internal counter to zero. This means that the lostData counter is synchronized with data logging: if it is non-zero, that number of Audit calls were unsuccessful immediately before this record.
  155. idCode    This value is the idCode parameter when Audit was called to store this record. Your application may use it for any purpose however, by convention, it is an OSType (four character string) that further identifies the Audit call.
  156. format    This is the format parameter when Audit was called to store this record. It defines the format of the rest of the record.
  157. data    This contains the actual data stored by the Audit call. There is enough space for up to eight longwords. Some format parameters store a string which can take up the remaining space. For example, if the only parameter is kAuditFormatString, up to 31 bytes (plus a one-byte length code) may be stored.
  158. While processing this data is not especially tricky, you may wish to re-read the sample code to unserstand how to format the data values.
  159. Audit RECORD Contents
  160. The Audit library keeps all information it needs in private structures. It is essential to understand that user applications must not modify these structure directly: they are described here for developers who need to modify the library for their own specific purposes. Note also that the following has been simplified slightly: the actual AuditRecord has some additional structures to preserve compatibility between Think C and MPW compilation conventions.
  161.  
  162. typedef struct AuditQueueEntry {
  163.     QElemPtr    qLink;    /* Queue linkage    */
  164.     AuditEntry    theEntry;    /* User’s data area    */
  165. } AuditQueueEntry, *AuditQueueEntryPtr;
  166.  
  167. typedef struct AuditRecord {
  168.     union {
  169.         void    *unusedLongword;
  170.         struct {
  171.             unsigned short    low;    /* Earliest lib version    */
  172.             unsigned short    high;    /* Latest lib version    */
  173.         } u;
  174.     } version;
  175.     unsigned long    recordSize;    /* Compiler check    */
  176.     unsigned long    lostData;    /* Missed log counter    */
  177.     void    *refNum;    /* User-controlled long    */
  178.     unsigned long    flags;    /* Logging & preference    */
  179.     unsigned long    timeAtStart;  /* GetDateTime()    */
  180.     unsigned long    ticksAtStart; /* TickCount()    */
  181.     ProcessSerialNumber    PSN;    /* Wakeup this process    */
  182.     unsigned long    logicalRAMSize; /* From Gestalt    */
  183.     QHdr    freeQueue;    /* Free queue header    */
  184.     QHdr    dataQueue;    /* Busy queue header    */
  185.     AuditQueueEntry    entries[1];    /* Entries stored here    */
  186. } AuditRecord, *AuditPtr;
  187. The structure elements are used as follows:
  188. version    This 32-bit value permits different versions of the Audit library to co-exist. InitAudit sets these values. Then, all calls to GetAuditPtr will verify that this instance of the library supports this AuditRecord format (I.e., is backwards compatible with earlier versions). version.u.low is the earliest library version supported; version.u.high is the latest. Each short is divided, by convention, into “major” and “minor” release identification values.
  189. If you modify the AuditRecord or AuditEntry definitions, your version of InitAudit should change its version identifier so that your AuditRecord will co-exist peacefully with other records that may be on your system.
  190. recordSize    This 32-bit value contains the sizes of the AuditRecord and AuditEntry. It prevents the program from crashing if a compiler changes the way it organizes data in memory.
  191. If you modify the AuditRecord or AuditEntry defintions, this value will be recomputed.
  192. lostData    This counter maintains the internal “lost data” counter. It is incremented whenever Audit cannot store an entry because there are no entries in the free queue, and is cleared to zero whenever Audit successfully stores an audit entry.
  193. flags    This word contains two flag bits: kAuditEnableMask is non-zero if logging is enabled. kAuditPreserveFirstMask is non-zero if data overflow should retain the first elements in the log. The flags variable is stored as a longword so that all record elements are aligned to 32-bit boundaries: this improves performance on modern hardware.
  194. timeAtStart    When the AuditRecord is created, this element receives the system time (seconds since the epoch).
  195. ticksAtStart    When the AuditRecord is created, this element receives the system ticks value.
  196. PSN    This identifies the process to awaken when data is stored in the Audit log. If the high longword is zero and the low longword is kNoProcess, no process will be awakened.
  197. logicalRAMSize    This is set to the end of logical RAM when the AuditRecord is created. Audit uses it to prevent a garbage address passed to the Audit string formatter from causing an address exception.
  198. freeQueue    This operating system queue stores the audit entries that are waiting to be filled by calls to Audit.
  199. dataQueue    This operating system queue stores the audit entries that have been filled and are waiting to be displayed by an application that calls ReadAudit.
  200. entries[]    This is a vector of AuditQueueEntry records that the Audit function uses to store data. An AuditQueueEntry is an AuditEntry prefaced by the Operating System Queue linkage pointer.
  201. InitAudit and GetAuditPtr return a pointer to the start of the AuditRecord. For reference, this record is preceded by a very small code segment that the system Gestalt manager calls when an application calls Gestalt. That code segment returns a pointer to the audit record. See the comments in Audit.c for details.
  202. FUNCTION USAGE
  203. The Audit library contains functions to create audit records, store data in an audit record, and extract data from an audit record. In addition, a number of functions that access records within an audit record are provided so the library can evolve without requiring application program modification and, especially, so that the library modifies its internal structures in a way that prevents two asychronous requests from changing a structure element at the same time.
  204. Creating an Audit Record
  205. AuditPtr
  206. InitAudit(
  207.     OSType    gestaltSelector,
  208.     unsigned short    nEntries,
  209.     Boolean    initiallyEnabled,
  210.     Boolean    preserveFirstEntries
  211. );
  212. InitAudit creates a new audit record as a non-relocatable object in the System Heap that is “named” by the gestaltSelector. The record will contain the indicated number of audit record entries. The initiallyEnabled parameter allows the caller choose whether to start logging when the record is created. If preserveFirstEntries is TRUE, Audit will not store data if there are no entries in the free queue. If preserveFirstEntries is FALSE, Audit will attempt to store data, even if it has to remove an entry from the "waiting for display" queue. InitAudit returns a pointer to the audit record it created or found, or NULL if it cannot create a record.
  213. As far as the Macintosh operating system is concerned, an audit record is a Gestalt selector function. This means that, once created, it cannot be deleted and its size cannot be changed. When creating a record, InitAudit will check for a pre-existing record, returning a pointer to that record if it exists. Thus, your gestaltSelector must not conflict with any existing selectors. Using your application’s creator ID might be appropriate.
  214. Several independent audit records can be active at any time, subject only to memory limitations and good taste.
  215. Finding an Existing Audit Record
  216. AuditPtr
  217. GetAuditPtr
  218.     OSType    gestaltSelector
  219. );
  220. GetAuditPtr returns a pointer to the audit record, or NULL if no record is defined for this selector. It also returns NULL if Gestalt returned a value that did not satisfy several internal consistency checks. This might happen if your program calls GetAuditPtr for a system Gestalt value, or if there was a severe version mismatch between the library that created the audit record and the library that is attempting to access it.
  221. Your application would typically call this function when it starts since, if an audit record is present, it will remain until your system is shutdown or restarted. The value returned by GetAuditPtr is used as a parameter to all other functions. Although your application could call GetAuditPtr each time it tries to log some data, this requires an internal call to Gestalt which would be inefficient.
  222. Writing an Audit Record Entry
  223. void
  224. Audit(
  225.     AuditPtr    auditPtr,
  226.     OSType    idCode,
  227.     unsigned long    format,
  228.     ...    /* Additional parameters, if any */
  229. );
  230. The Audit function stores an entry in the audit record that contains the following data:
  231. •    Audit timestamps each entry with the system Ticks() value. As will be seen, your display procedure can convert this value into civil time (hours, minutes, seconds) when the entry is displayed.
  232. •    idCode is a value that you specify. By convention, it is assumed to be an OSType that the display application uses to identify the audit request. This may be a unique value for each request or a value that is common to a group of requests (such as a single function or function library). Audit does not interpret this value, however the MacsBug display routine (dcmd) interpretes it as an OSType. Note that, on the Macintosh, an OSType can be coerced to any longword scalar, such as a memory address. As you adapt the Audit library to your own use, you may wish to consider passing some state information in the idCode parameter (perhaps a pointer to a task-specific handle) rather than using it as a human-readable identifier.
  233. •    format is a 32-bit value that the Audit function interprets to understand how to process the additional parameters, if any. It should be set to the result of expanding the AuditFormat macro, or one of two special values. It will be described below.
  234. •    Your program up to eight longword arguments. The format parameter tells Audit and the display procedure how to interpret these arguments, if any.
  235. Note: because of differences between various C compilers, it is essential that your program specify all data parameters as longwords. For example, if you wish to log a value that is normally stored as a short value, such as a system error code or Boolean, your program must explicitly cast it to long or unsigned long. If you don’t do this, you will display incorrect data. The Audit library operates compatibly under both MPW and Think C. An application written in one environment can access an Audit Record created by the other environment.
  236. Of course, Audit will only store an entry if several conditions are met:
  237. •    AuditPtr must be non-NULL. It is the value returned by GetAuditPtr or InitAudit. If it is NULL, Audit silently returns.
  238. •    The version number and record size values must be acceptable.
  239. •    Auditing must have been enabled, either by InitAudit or EnableAudit.
  240. •    There must be room for the entry in the audit entry area. This test will fail if your display function does not read audit record entries quickly enough and will be discussed further.
  241. Formatting Audit parameters
  242. In order to simplify audit display applications, each audit record entry is self-formatting. The format parameter specifies the format of all additional parameters. The format parameter should be constructed by expanding the AuditFormat macro. For most uses, you would use AuditFormat1, AuditFormat2, etc. which call AuditFormat with the proper argument sequence.
  243. The following, if present, must be the last — or only — AuditFormat argument specification:
  244. kAuditFormatString    This must be the last parameter in an AuditFormat specification. Audit requires one additional parameter, a Pascal string. If it is the only parameter, the first 31 bytes of the string will be stored. If other parameters preceed this, as many bytes as can fit will be stored (each argument requires four bytes). Your program does not need to concern itself with string length; the Audit function truncates the data as needed. Note: if the parameter is bad (NULL or greater than the logical RAM size, it will display “?NN” where NN is the value of the argument in Hex
  245. kAuditFormatStatusLocation    This must be the last parameter in an AuditFormat specification. There is no associated parameter. The Audit function stores the name and offset of the caller in the audit record, truncating the string as needed.
  246. The following may appear anywhere in the AuditFormat operation. Each argument defines the format of an associated Audit parameter:
  247. kAuditFormatSigned    A signed integer longword value.
  248. kAuditFormatUnsigned    An unsigned integer longword value.
  249. kAuditFormatHex    An unsigned hexadecimal value that may be interpreted as a 4-byte character, such as an OSType or ResType value. This is displayed both in hexadecimal and as a character string (with ‘.’ replacing any non-printable bytes).
  250. kAuditFormatAddress    An unsigned hexadecimal value that is never interpreted as a character string.
  251. kAuditFormatEnd    This terminates the list of parameters. The AuditFormat1, etc. macros append this as needed: by using these macros, you do not need to be concerned with this value.
  252. In order to simplify the life of the poor programmer, the header file provides a family of macros that allow you to specify one to eight arguments. Thus, instead of writing
  253. Audit(
  254.     auditPtr,
  255.     'Moof',
  256.     AuditFormat(
  257.         kAuditFormatSigned,    kAuditFormatEnd,    kAuditFormatEnd,    kAuditFormatEnd,
  258.         kAuditFormatEnd,        kAuditFormatEnd,    kAuditFormatEnd,    kAuditFormatEnd),
  259.     (long) 12345
  260. );
  261. you can write
  262.     Audit(auditPtr, 'Moof', AuditFormat1(kAuditFormatSigned), (long) 12345);
  263. Note that the function call explicitly casts the integer parameter to long.
  264. The header file provides AuditFormat1, AuditFormat2, …, AuditFormat8 macros. 
  265. Writing a String to the Audit Record
  266. void
  267. AuditString(
  268.     AuditPtr    auditPtr,
  269.     OSType    idCode,
  270.     const StringPtr    string
  271. );
  272. The AuditString function stores a string in a single Audit record entry. It is actually implemented as a macro as follows:
  273.  
  274. #define AuditString(auditPtr, idCode, string) (                    \
  275.         Audit(                                                            \
  276.             (auditPtr),                                                \
  277.             (idCode),                                                    \
  278.             AuditFormat1(kAuditFormatString),                        \
  279.             string                                                        \
  280.         )                                                                \
  281.     )
  282. Writing a Status Error to the Audit Record
  283. void
  284. AuditStatusString(
  285.     AuditPtr    auditPtr,
  286.     OSType    idCode,
  287.     OSErr    status,
  288.     const StringPtr    string
  289. );
  290. The AuditStatusString function stores an operating-system status code and accompaning descriptive string in a single Audit record entry. 
  291. void
  292. AuditStatusLocation(
  293.     AuditPtr    auditPtr,
  294.     OSType    idCode,
  295.     OSErr    status
  296. );
  297. The AuditStatusLocation function stores an operating-system status code and the location of the call in a single Audit record entry. The location uses the MacsBug name and is similar to the string that would be displayed by the MacsBug ‘sc6’ command.
  298. Both AuditStatusString and AuditStatusLocation are implemented as macros that call Audit with the proper format expression. 
  299. Reading an Audit Record Entry
  300. Boolean
  301. ReadAudit(
  302.     AuditPtr    auditPtr,
  303.     AuditEntryPtr    thisLogEntry
  304. );
  305. If there is an audit record entry waiting for this audit record, ReadAudit copies it to your entry buffer and returns TRUE. If nothing is waiting (or auditPtr is NULL), it returns FALSE. Note that ReadAudit does not care whether audit logging is currently enabled.
  306. If ReadAudit returns FALSE, no additional data is returned.
  307. ReadAudit copies its internal audit entry to the buffer that your program specifies. Then it immediately returns the buffer to the free buffer list . A subsequent section of this document describes the content of an AuditEntry record. 
  308. Formatting the Audit Record Entry Data
  309. void
  310. FormatAuditEntryData(
  311.     AuditEntryPtr    entryPtr,
  312.     StringPtr    result
  313. );
  314. FormatAuditEntryData converts the data in the entry to a readable string, storing the formatted output in the result string. It does not display the data, nor does it convert the timestamp. The FormatAuditEntryData function  is provided in AuditEntryFormat.c. It may need to be mofified for non-English usage.
  315. Formatting the Audit Record Entry Timestamp
  316. void
  317. FormatAuditEntryTimestamp(
  318.     AuditPtr    auditPtr,
  319.     AuditEntryPtr    entryPtr,
  320.     StringPtr    result
  321. );
  322. FormatAuditEntryTimestamp converts the entry’s timestamp to a readable string, storing the formatted output in result. The output is a fixed-length string with the following format:
  323. 1992.12.25 22:10:44.123
  324. The result contains the year, month, and date (in ISO-date format), followed by the time of day in 24-hour clock format with the residual clock ticks (in milliseconds). This format is independent of the time and date formatting selected by the computer user. The FormatAuditEntryTimestamp function  is provided in AuditEntryFormat.c. 
  325. Support Functions
  326. Your application should use the following functions to access an audit record’s internal structure. They also make it possible to extend the library without requiring changes in an application program. All audit record structure elements must be accessed through these functions as they prevent two interrupt-driven code sequences from accessing structure elements simultaneously.
  327. Specifying the Display Application
  328. void
  329. WakeUpAudit(
  330.     AuditPtr    auditPtr,
  331.     ProcessSerialNumber    *oldPSN
  332. );
  333. If your application is running under a version of the operating system that supports the Process Manager, it can specify the application that should run whenever an entry is written into this audit record. Your application should set its process serial number in oldPSN before calling WakeUpAudit. On return, oldPSN is set to the previous display application. 
  334. Enabling and Disabling Audit Logging
  335. Boolean
  336. EnableAudit(
  337.     AuditPtr    auditPtr,
  338.     Boolean    enableLogging
  339. );
  340. If enableLogging is TRUE, calls to Audit will store data in the audit record (assuming, of course, that there is room to store data). If the parameter is FALSE, Audit will ignore calls for this audit record. EnableAudit returns the old value of the enabling flag; thus your application can restore the previous audit log state.
  341. Testing Whether Audit Logging is Enabled
  342. Boolean
  343. IsAuditEnabled(
  344.     AuditPtr    auditPtr
  345. );
  346. This function returns the current value of the enable flag. It returns FALSE if auditPtr is NULL or audit logging is disabled.
  347. Controlling Data Overrun
  348. Boolean
  349. PreserveAudit(
  350.     AuditPtr    auditPtr,
  351.     Boolean    preserveFirst
  352. );
  353. If preserveFirst is TRUE and Audit is called when there is no room to store data, Audit will ignore the call request, preserving the entries waiting to be displayed. If preserveFirst is FALSE, Audit will throw away the first (earliest) entry in the “to be displayed” queue, thus retaining the latest nEntries worth of data. PreserveAudit returns the old value of the preserveFirst flag; thus your application can restore the previous audit state. Note that there is no “right” value for this flag: different applications require different preservation strategies.
  354. Retrieving Audit Log Creation Times
  355. void
  356. GetAuditStartTimes(
  357.     AuditPtr    auditPtr,
  358.     unsigned long    *timeAtStart,
  359.     unsigned long    *ticksAtStart
  360. );
  361. Your display application should call this function to get the actual time that the audit record was created. Using these values and the timestamp returned in each audit entry record, your display application can convert the audit entry timestamp to civil time (date and time).
  362. Accessing the User-controlled Reference Value
  363. void *
  364. SetAuditRefNum(
  365.     AuditPtr    auditPtr,
  366.     void    *refNum
  367. );
  368. void *
  369. GetAuditRefNum(
  370.     AuditPtr    auditPtr
  371. );
  372. This pair of functions allows your application to set and retrieve a user-controlled value that may be coerced to any scalar value (such as a memory pointer). SetAuditRefNum returns the previous refNum value. Both functions return zero if auditPtr is NULL or no value had been stored. Your application may use this value for any purpose.
  373.  
  374.